home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Special 16 / AMIGAplus Sonderheft 16 (1998)(ICP)(DE)[!].iso / pd / anwendungen / ispell-3.1.18bin / interfaces / gnu-emacs / autofix.el next >
Lisp/Scheme  |  1995-09-21  |  12KB  |  289 lines

  1.  
  2. ;; ** WARNING ** WARNING ** WARNING ** WARNING ** WARNING ** WARNING **
  3.  
  4. ;; This will ONLY work with the ispell.el in the >> local << directory of
  5. ;; HUGE.  It will NOT work with vanilla emacs ispell.el.  Make sure that
  6. ;; emacs/lisp/local is in your load path before emacs/lisp, or explicitly
  7. ;; load the local version of ispell.  It will fail otherwise.
  8.  
  9. ;; Also, your ispell must be working correctly in order for this to work.
  10.  
  11. ;; ***************************************************************************
  12. ;;
  13. ;; DESCRIPTION: Minor mode to fix misspelled words as they are typed.
  14. ;; AUTHOR     : Steve Koren
  15. ;; DATE       : 27 Apr Pr
  16. ;; VERSION    : 1.1
  17. ;; STATUS     : Experimental beta version
  18. ;;
  19. ;; This code is provided under the GNU liscence, and may be freely
  20. ;; distributed and copied provided that further distribution is not
  21. ;; restricted.  There is no warrenty on this software; it is provided free
  22. ;; of charge and therefor "as-is".
  23. ;;
  24. ;; This ELISP code provides a minor mode for automatically fixing some
  25. ;; types of spelling and typing mistakes on English words in real time as
  26. ;; they are typed.  It can also beep passively upon spelling errors
  27. ;; without making any modifications to the text.
  28.  
  29. ;; When a word delimiter is typed (usually space or punctuation), the
  30. ;; previous word is looked up in the dictionary via ispell.  If
  31. ;; autofix-autochange is t and there is only one suggested replacement
  32. ;; for the misspelled word, then the replacement is substituted
  33. ;; automatically with no further action required, and emacs beeps to
  34. ;; signal this fact.  When there is only one suggestion it is right most
  35. ;; of the time, and the word will be fixed with no further effort on your
  36. ;; part.  If autofix-autochange is nil, then no word replacements are
  37. ;; performed, but emacs will still beep after any misspelled words.
  38. ;;
  39. ;; autofix-mode likes a fast machine since it looks up every word you type
  40. ;; as you type it.  The overhead is unnoticeable on an HP-720.  A 68030
  41. ;; or better will probably do.
  42. ;;
  43. ;; Although the minor mode must remap the local definitions of the word
  44. ;; delimiters (space, ".", etc), it makes a heroic effort to use the
  45. ;; original definition of the key after it is called.  Thus, it should
  46. ;; coexist peacefully with other minor modes and custom keymaps which
  47. ;; themselves define mappings for various keys.  It does this by saving
  48. ;; the original local keymap when autofix-mode is started, and then
  49. ;; rebinding the keys to its needs.  When a rebound key is used, the
  50. ;; standard autofix lookup is performed, and then the definition of the
  51. ;; key from the saved keymap is used.
  52.  
  53. ;; ***************************************************************************
  54.  
  55.  
  56. ;; ***************************************************************************
  57. ;; variables to store state of minor mode
  58. ;; ***************************************************************************
  59.  
  60. (defvar autofix-mode        nil "t if autofix mode is active, else nil")
  61. (defvar autofix-old-map     nil "autofix-mode original local keymap")
  62.  
  63. (defvar autofix-break-chars " \t\r.,;?!"
  64.   "*autofix will check words after these characters are typed")
  65.  
  66. (defvar autofix-autochange t
  67.   "*t if autofix-mode should auto-change misspelled words.  nil to just beep")
  68.  
  69. (defvar autofix-be-silent nil
  70.   "*t if autofix-mode should be quiet (not beep) for misspellings")
  71.  
  72. (defvar autofix-be-aggressive nil
  73.   "* if autofix-mode should be aggressive in finding replacements")
  74.  
  75. (make-variable-buffer-local 'autofix-mode)
  76. (make-variable-buffer-local 'autofix-old-map)
  77.  
  78. ;; ***************************************************************************
  79. ;; Add our minor mode to the minor-mode-alist if its not there already
  80. ;; ***************************************************************************
  81.  
  82. (or (assq 'autofix-mode minor-mode-alist)
  83.     (setq minor-mode-alist
  84.           (cons '(autofix-mode " AutoFix") minor-mode-alist)))
  85.  
  86.  
  87. ;; ***************************************************************************
  88. ;; Function to turn on and off our minor mode
  89. ;; ***************************************************************************
  90.  
  91. (defun autofix-mode (arg)
  92.   "Toggle auto-fix mode.
  93.  
  94. With arg, turn auto-fix mode on iff arg is positive.
  95.  
  96. In auto-fix mode, typing a space or punctuation character spell
  97. checks the previous word, beeps if not found in the dictionary,
  98. and inserts a correction if there is only one available and
  99. autofix-autochange is t.  For example, \"definision\" will be
  100. changed to \"definition\".  autofix-mode words best with text
  101. oriented major modes such as text-mode.
  102.  
  103. Note: Since this mode depends on ispell, your ispell must be working
  104. correctly in order for autofix-mode to work.
  105.  
  106. Suggestion: If there are commonly misspelled words which autofix is
  107. unable to correct, put them in a mode specific abbreviation table
  108. and turn on abbrev-mode in addition to autofix-mode.
  109.  
  110. The following variables are used by autofix-mode and can be set
  111. in a .emacs file:
  112.  
  113.   autofix-break-chars  - A string of characters which autofix
  114.                          will change the definition of in the local
  115.                          keymap.  The original definitions are
  116.                          called after autofix does its work.  Also,
  117.                          autofix-mode restores the original keymap
  118.                          after it is turned off.
  119.  
  120.   autofix-be-silent    - Set this to t to stop autofix from
  121.                          beeping.  Automatic changes will still be
  122.                          made.  Defaults to nil.
  123.  
  124.   autofix-autochange   - Set this to nil to stop autofix from
  125.                          making corrections if it finds a reasonable
  126.                          substitution for the misspelled word.  It
  127.                          will then only beep for misspellings.
  128.                          Defaults to t.
  129.  
  130.   autofix-be-aggressive- Set to t if autofix should be more
  131.                          aggressive when finding word replacements.
  132.                          When being aggressive, autofix will replace
  133.                          words even if it sees more than one
  134.                          possible replacement.  It will pick the
  135.                          first one, which may or may not be correct.
  136.                          Defaults to nil.  Use with caution.
  137. "
  138.  
  139.   (interactive "P")
  140.  
  141.   ; -- set the autofix-mode variable appropriately ---------------------------
  142.  
  143.   (setq autofix-mode
  144.     (if (null arg) (not autofix-mode)
  145.       (> (prefix-numeric-value arg) 0)))
  146.  
  147.   ; -- if we have a local keymap, fix it up ----------------------------------
  148.  
  149.   (if (current-local-map)
  150.       (if autofix-mode
  151.           ; -- install the new meanings --------------------------------------
  152.           (progn
  153.             ; -- save the original keymap so we can restore it later ---------
  154.             (setq autofix-old-map (current-local-map))
  155.  
  156.             ; -- now make a new local keymap we can mess with ----------------
  157.             (use-local-map (copy-keymap (current-local-map)))
  158.  
  159.             (let ((x 0))
  160.               (while (< x (length autofix-break-chars))
  161.                 (define-key (current-local-map)
  162.                   (substring autofix-break-chars x (+ x 1))
  163.                   'afix-rt-check
  164.                 )
  165.                 (setq x (+ x 1))
  166.               )
  167.             )
  168.           )
  169.  
  170.         ; -- restore the old keymap ------------------------------------------
  171.         (use-local-map autofix-old-map)
  172.       )
  173.   )
  174.  
  175.   ; -- no-op, but updates the mode line --------------------------------
  176.  
  177.   (set-buffer-modified-p (buffer-modified-p))
  178. )
  179.  
  180. ;; ***************************************************************************
  181. ;; load ispell if it is not loaded.  Ispell has no (provide) so we have to do
  182. ;; it this way.  Also, we attempt to check for the right ispell.
  183. ;; ***************************************************************************
  184.  
  185. (if (not (boundp 'ispell-syntax-table))  ;; load ispell if not loaded
  186.     (load-library "ispell"))
  187.  
  188. (if (not (boundp 'ispell-syntax-table))  ;; check for proper version
  189.     (error "Wrong version of ispell - no syntax table!"))
  190.  
  191.  
  192. ;; ***************************************************************************
  193. ;; If the previous character is a word element, the word is looked up via
  194. ;; afix-word.
  195. ;; Changed 28 Apr 92 to stop trying to check numbers.
  196. ;; ***************************************************************************
  197.  
  198. (defun afix-rt-check ()
  199.  
  200.   "Checks the previous word in the dictionary using afix-word."
  201.  
  202.   (interactive)
  203.  
  204.   ; -- here we call afix-word if necessary -----------------------------------
  205.  
  206.   (if (> (point) 1)
  207.       (if (= (char-syntax (preceding-char)) ?w)
  208.           (if (or (< (preceding-char) ?0) (> (preceding-char) ?9))
  209.               (afix-word)
  210.           )
  211.       )
  212.   )
  213.   
  214.   ; -- Here we perform the action the key was supposed to have.  This is -----
  215.   ; -- done by first looking for a local keybinding, and if found, -----------
  216.   ; -- executing that.  If there is no local binding, use the global one. ----
  217.  
  218.   (let ((cmd (lookup-key autofix-old-map (char-to-string last-input-char))))
  219.     (if cmd
  220.         (call-interactively cmd)
  221.       (call-interactively (global-key-binding 
  222.                            (char-to-string last-input-char)))
  223.     )
  224.   )
  225. )
  226.  
  227.  
  228. ;; ***************************************************************************
  229. ;; This code is basically lifted verbatim from ispell.el, but the interactive
  230. ;; functions have been replaced with either t or beep, accordingly.  I
  231. ;; neither know nor want to know how it works.  I just modified it enough
  232. ;; to do what is needed.
  233. ;; ***************************************************************************
  234.  
  235. (defun afix-word ()
  236.    "Check spelling of word at or before dot."
  237.    (interactive)
  238.    (let* ((current-syntax (syntax-table))
  239.           start end word poss replace)
  240.       (unwind-protect
  241.             (save-excursion
  242.                (set-syntax-table ispell-syntax-table)            ;; Ensure syntax table is reasonable 
  243.                (if (not (looking-at "\\w"))
  244.                    (re-search-backward "\\w" (point-min) 'stay)) ;; Move backward for word if not already on one
  245.                (re-search-backward "\\W" (point-min) 'stay)      ;; Move to start of word
  246.                (or (re-search-forward "\\w+" nil t)              ;; Find start and end of word
  247.                    (error "No word to check."))
  248.                (setq start (match-beginning 0)
  249.                      end (match-end 0)
  250.                      word (buffer-substring start end)))
  251.          (set-syntax-table current-syntax))
  252.       (ispell-init-process)   ;; erases ispell output buffer
  253.  
  254.       (if (boundp 'amiga-initialized)
  255.           ;; -- use amiga ispell ARexx port ----------------------------------
  256.           (setq poss (ispell-parse-output (amiga-ispell-lookup word)))
  257.  
  258.         ;; -- else use Unix ispell process -----------------------------------
  259.  
  260.         (save-excursion
  261.           (set-buffer ispell-out-name)
  262.           (send-string ispell-process (concat word "\n"))
  263.           (while (progn            ;; Wait until we have a complete line
  264.                    (goto-char (point-max))
  265.                    (/= (preceding-char) ?\n))
  266.             (accept-process-output ispell-process))
  267.           (goto-char (point-min))
  268.           (setq poss (ispell-parse-output
  269.                       (buffer-substring (point) 
  270.                                         (progn (end-of-line) (point))))))
  271.         )
  272.  
  273.       (cond ((eq poss t)
  274.              t)
  275.             ((stringp poss)
  276.              t)
  277.             ((null poss)
  278.              (or autofix-be-silent (beep)))
  279.             (t (if (and autofix-autochange
  280.                         (or autofix-be-aggressive (= (length poss) 1)))
  281.                    (progn (backward-kill-word 1)
  282.                           (insert (car poss))
  283.                    )
  284.                )
  285.                (or autofix-be-silent (beep))
  286.             ))
  287.  
  288.       poss))
  289.